package com.kun.companion.core.ui.button;

import cn.hutool.core.util.StrUtil;
import com.kun.companion.core.queue.ButtonEvent;
import com.kun.companion.core.util.ComUtil;
import javafx.animation.*;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.css.PseudoClass;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.CacheHint;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.SVGPath;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;

/**
 * 抽象按钮基类，提供统一的交互动画、状态管理和事件处理机制。
 * 特性：
 * 1. 支持悬停/按压状态动画（淡入淡出、缩放效果）
 * 2. 按钮操作队列化处理，防止重复提交
 * 3. CSS伪类状态自动管理
 * 4. 线程安全的共享动画资源（享元模式）
 *
 * @author gzc
 * @since 2025/2/5
 **/
public abstract class AbstractButton extends Button {
    private static final Logger log = LoggerFactory.getLogger(AbstractButton.class);
    /**
     * 默认透明度
     */
    private static final double DEFAULT_OPACITY = 0.9;
    /**
     * 动画持续时间
     */
    private static final Duration DEFAULT_ANIM_DURATION = Duration.millis(0);
    /**
     * CSS伪类定义
     */
    private static final PseudoClass HOVER_PSEUDO_CLASS = PseudoClass.getPseudoClass("hover");
    private static final PseudoClass PRESSED_PSEUDO_CLASS = PseudoClass.getPseudoClass("pressed");
    /**
     * 享元模式共享动画资源
     */
    private static volatile FadeTransition sharedFadeIn;
    private static volatile FadeTransition sharedFadeOut;
    /**
     * 状态标志位（使用位运算优化内存占用）
     */
    private byte stateFlags = 0b00000000;
    private static final byte HOVER_FLAG = 0b00000001;
    private static final byte PRESSED_FLAG = 0b00000010;
    /**
     * 点击按钮后，执行事件时的加载中动画
     */
    private Circle progressIndicator;
    private RotateTransition loadingAnimation;
    /**
     * 按钮图标
     */
    private final ObjectProperty<Object> svgGraphicProperty = new SimpleObjectProperty<>(this, "svgGraphic");
    /**
     * 按钮文本
     */
    protected Label textLabel;
    /**
     * 操作状态
     */
    protected boolean isProcessing = false;
    /**
     * 按钮事件
     */
    protected ButtonEvent buttonEvent;
    /**
     * 上一次触发的事件ID
     */
    protected String lastEventId;

    /**
     * 复用的事件处理器（减少对象创建）
     */
    private final EventHandler<MouseEvent> stateHandler = this::handleStateEvent;

    static {
        initSharedAnimations();
    }

    protected AbstractButton(Node svgGraphic, String tipText) {
        this(null, svgGraphic, tipText);
    }

    protected AbstractButton(String buttonText) {
        this(buttonText, null, buttonText);
    }

    protected AbstractButton(String buttonText, String tipText) {
        this(buttonText, null, tipText);
    }

    /**
     * 构造抽象按钮
     *
     * @param buttonText 按钮显示文本
     * @param svgGraphic 按钮图形（SVG节点）
     * @param tipText    悬浮提示文本
     */
    protected AbstractButton(String buttonText, Node svgGraphic, String tipText) {
        withText(buttonText);
        withTooltip(tipText);
        initBaseConfig();
        createAnimation();
        withSvgGraphic(svgGraphic);
        setOnAction(this::handleButtonAction);
        registerStateListeners();
    }

    /**
     * 设置按钮文本
     *
     * @param text 按钮文本
     * @return 当前按钮实例（支持链式调用）
     */
    public <T extends AbstractButton> T withText(String text) {
        setText(text);
        return (T) this;
    }

    /**
     * 添加样式类
     *
     * @param styleClass 样式类名称
     * @return 当前按钮实例（支持链式调用）
     */
    public <T extends AbstractButton> T withStyleClass(String styleClass) {
        getStyleClass().add(styleClass);
        return (T) this;
    }

    /**
     * 设置悬浮提示文本
     *
     * @param tooltipText 提示文本
     * @return 当前按钮实例（支持链式调用）
     */
    public <T extends AbstractButton> T withTooltip(String tooltipText) {
        if (StrUtil.isNotBlank(tooltipText)) {
            setTooltip(new Tooltip(tooltipText));
        }
        return (T) this;
    }

    /**
     * 设置SVG图形
     *
     * @param svgGraphic SVG图形节点
     * @return 当前按钮实例（支持链式调用）
     */
    public <T extends AbstractButton> T withSvgGraphic(Node svgGraphic) {
        setGraphic(createGraphicContainer(textLabel, svgGraphic));
        return (T) this;
    }

    /**
     * 设置SVG图形
     *
     * @param svgGraphic SVG图形节点
     */
    public final void setSvgGraphic(Object svgGraphic) {
        SVGPath svgPath = null;
        if (svgGraphic instanceof String svgGraphicText) {
            svgPath = new SVGPath();
            svgPath.setContent(svgGraphicText);
        }
        svgGraphicProperty.bind(graphicProperty());
        setGraphic(createGraphicContainer(textLabel, svgPath));
    }

    public final Object getSvgGraphic() {
        return getGraphic();
    }

    /**
     * 创建按钮事件对象（抽象方法需子类实现）
     *
     * @return QueueButtonEvent
     */
    public abstract ButtonEvent createButtonEvent();

    /**
     * 创建图形容器（供子类扩展实现自定义包装）
     *
     * @param svgGraphic 原始图形节点
     * @return 包装后的图形节点
     */
    protected Node createGraphicContainer(Label textLabel, Node svgGraphic) {
        String buttonText = textLabel.getText();
        // 创建堆叠布局容器
        StackPane stackPane = new StackPane();
        stackPane.setAlignment(Pos.CENTER);
        if (svgGraphic != null && StrUtil.isBlank(buttonText)) {
            // 将文本和指示器添加到容器
            stackPane.getChildren().addAll(svgGraphic, progressIndicator);
            // 图标和文本的位置
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        if (svgGraphic == null && StrUtil.isNotBlank(buttonText)) {
            // 将文本和指示器添加到容器
            stackPane.getChildren().addAll(textLabel, progressIndicator);
            // 图标和文本的位置
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        if (svgGraphic != null && StrUtil.isNotBlank(buttonText)) {
            HBox hBox = new HBox();
            hBox.getChildren().addAll(svgGraphic, textLabel);
            stackPane.getChildren().addAll(hBox, progressIndicator);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        if (svgGraphic == null && StrUtil.isBlank(buttonText)) {
            // 将文本和指示器添加到容器
            stackPane.getChildren().addAll(progressIndicator);
        }

        return stackPane;
    }

    /**
     * 更新UI状态
     * 1. 禁用按钮防止重复点击
     * 2. 添加/移除处理中样式
     */
    protected void updateUIState() {
        ComUtil.uiThreadRun(() -> {
            setDisable(isProcessing);
            progressIndicator.setVisible(isProcessing);
            // 处理时隐藏文本
//            textLabel.setVisible(!isProcessing);
            if (isProcessing) {
                loadingAnimation.play();

//                getStyleClass().add("processing");
            } else {
                loadingAnimation.stop();
                // 重置旋转角度
                progressIndicator.setRotate(0);
//                getStyleClass().remove("processing");
            }
        });
    }

    /* 模板方法（供子类覆盖） */

    /**
     * 应用按下样式（默认缩小5%）
     */
    protected void applyPressedStyle() {
//        setScaleX(0.95);
//        setScaleY(0.95);
    }

    /**
     * 应用释放样式（默认恢复原尺寸）
     */
    protected void applyReleaseStyle() {
//        setScaleX(1.0);
//        setScaleY(1.0);
    }

    /**
     * 核心点击事件处理
     * 1. 防止重复提交
     * 2. 创建事件对象
     * 3. 执行异步处理
     */
    protected void handleButtonAction(ActionEvent actionEvent) {
        if (isProcessing) {
            return;
        }
        isProcessing = true;
        updateUIState();
        // 如果未调用action方法buttonEvent对象为空，则调用子类实现的createButtonEvent获取ButtonEvent对象
        if (buttonEvent == null) {
            ButtonEvent buttonEvent = createButtonEvent();
            actionEvent(buttonEvent);
        }
        lastEventId = buttonEvent.eventId();
        doHandleAction(buttonEvent, this::handleSuccess, this::handleFailure);
    }

    /**
     * 执行按钮点击事件具体逻辑
     *
     * @param buttonEvent 按钮点击事件具体逻辑
     */
    public void actionEvent(ButtonEvent buttonEvent) {
        this.buttonEvent = buttonEvent;
    }

    public void action(Runnable runnableEvent) {
        this.buttonEvent = runnableEvent::run;
    }

    /**
     * 执行具体业务逻辑（模板方法）
     *
     * @param event           按钮事件对象
     * @param successCallback 成功回调
     * @param failureCallback 失败回调
     * @return CompletableFuture对象用于异步处理
     */
    protected CompletableFuture<Void> doHandleAction(ButtonEvent event,
                                                     Runnable successCallback,
                                                     Runnable failureCallback) {
        return CompletableFuture.runAsync(() -> {
            try {
                event.execute();
                successCallback.run();
            } catch (Exception e) {
                log.error("按钮操作执行失败: {}", e.getMessage(), e);
                failureCallback.run();
            }
        });
    }

    public final void setAction(EventHandler<ActionEvent> value) {
        onActionProperty().set(value);
    }

    public final EventHandler<ActionEvent> getAction() {
        return onActionProperty().get();
    }

    /**
     * fxml文件中调用
     */
    @Override
    public void fire() {
        handleButtonAction(null);
    }

    /**
     * 处理操作成功
     * 1. 更新状态
     * 2. 显示成功样式（2秒后自动移除）
     */
    protected void handleSuccess() {
        isProcessing = false;
        ComUtil.uiThreadRun(() -> {
            updateUIState();
            addTempStyleClass("success", Duration.seconds(2));
        });
    }

    /**
     * 处理操作失败
     * 1. 更新状态
     * 2. 显示错误样式（2秒后自动移除）
     */
    protected void handleFailure() {
        isProcessing = false;
        ComUtil.uiThreadRun(() -> {
            updateUIState();
            addTempStyleClass("error", Duration.seconds(2));
        });
    }

    private void createAnimation() {
        // 加载动画指示器
        progressIndicator = new Circle(8);
        progressIndicator.setVisible(false);
        progressIndicator.setMouseTransparent(true);
        progressIndicator.setStroke(Color.BLUE);
        // 虚线边框
        progressIndicator.getStrokeDashArray().addAll(5.0, 5.0);
        progressIndicator.setFill(Color.TRANSPARENT);
        progressIndicator.setStrokeWidth(2);
        // 设置几何中心（如果布局有偏移）
        progressIndicator.setCenterX(progressIndicator.getRadius());
        progressIndicator.setCenterY(progressIndicator.getRadius());
        // 层级提升
        progressIndicator.setTranslateZ(1);

        // 旋转动画配置
        loadingAnimation = new RotateTransition(Duration.seconds(1), progressIndicator);
        loadingAnimation.setByAngle(360);
        loadingAnimation.setCycleCount(Animation.INDEFINITE);
        loadingAnimation.setInterpolator(Interpolator.LINEAR);
        // 明确旋转轴
        loadingAnimation.setAxis(Rotate.Z_AXIS);
    }

    /**
     * 初始化基础配置
     * 1. 启用硬件加速
     * 2. 优化点击检测
     * 3. 初始化默认样式
     */
    private void initBaseConfig() {
        // 启用缓存加速渲染
        setCache(true);
        // 优化渲染性能
        setCacheHint(CacheHint.SPEED);
        // 精确点击区域检测
        setPickOnBounds(true);
        // 避免亚像素渲染
        setSnapToPixel(true);
        getStyleClass().add("kun-button");
        setOpacity(DEFAULT_OPACITY);
        // 创建独立文本标签（与按钮文本绑定）
        textLabel = new Label(getText());
        // 绑定按钮文本
        textLabel.textProperty().bind(textProperty());

    }


    /**
     * 注册鼠标状态监听器
     * 使用单一处理器统一管理四类事件：
     * 1. 鼠标进入
     * 2. 鼠标离开
     * 3. 鼠标按下
     * 4. 鼠标释放
     */
    private void registerStateListeners() {
        addEventFilter(MouseEvent.MOUSE_ENTERED, stateHandler);
        addEventFilter(MouseEvent.MOUSE_EXITED, stateHandler);
        addEventFilter(MouseEvent.MOUSE_PRESSED, stateHandler);
        addEventFilter(MouseEvent.MOUSE_RELEASED, stateHandler);
    }

    /**
     * 统一处理鼠标状态事件
     *
     * @param event 鼠标事件对象
     */
    private void handleStateEvent(MouseEvent event) {
        switch (event.getEventType().getName()) {
            case "MOUSE_ENTERED" -> handleHoverStart();
            case "MOUSE_EXITED" -> handleHoverEnd();
            case "MOUSE_PRESSED" -> handlePressStart();
            case "MOUSE_RELEASED" -> handlePressEnd();
            default -> {/* 忽略其他事件 */}
        }
        updatePseudoClassStates();
    }

    /**
     * 更新CSS伪类状态
     * 根据状态标志位自动更新:hover和:pressed状态
     */
    private void updatePseudoClassStates() {
        pseudoClassStateChanged(HOVER_PSEUDO_CLASS, (stateFlags & HOVER_FLAG) != 0);
        pseudoClassStateChanged(PRESSED_PSEUDO_CLASS, (stateFlags & PRESSED_FLAG) != 0);
    }

    /* 状态处理方法组 */
    private void handleHoverStart() {
        stateFlags |= HOVER_FLAG;
        playHoverAnimation(true);
    }

    private void handleHoverEnd() {
        stateFlags &= ~HOVER_FLAG;
        playHoverAnimation(false);
    }

    private void handlePressStart() {
        stateFlags |= PRESSED_FLAG;
        applyPressedStyle();
    }

    private void handlePressEnd() {
        stateFlags &= ~PRESSED_FLAG;
        applyReleaseStyle();
    }

    /**
     * 初始化共享动画资源（线程安全）
     */
    private static synchronized void initSharedAnimations() {
        if (sharedFadeIn == null) {
            sharedFadeIn = createFadeTransition(1.0);
            sharedFadeOut = createFadeTransition(DEFAULT_OPACITY);
        }
    }

    /**
     * 播放悬停动画（支持延迟初始化）
     *
     * @param enter true: 鼠标进入动画，false: 鼠标离开动画
     */
    private void playHoverAnimation(boolean enter) {
        // 双重检查锁定确保线程安全
        if (sharedFadeIn == null) {
            synchronized (AbstractButton.class) {
                if (sharedFadeIn == null) {
                    sharedFadeIn = createFadeTransition(1.0);
                    sharedFadeOut = createFadeTransition(DEFAULT_OPACITY);
                }
            }
        }

        FadeTransition anim = enter ? sharedFadeIn : sharedFadeOut;
        if (anim.getStatus() == Animation.Status.RUNNING) {
            // 停止正在运行的动画避免冲突
            anim.stop();
        }
        // 绑定当前节点
        anim.setNode(this);
        anim.playFromStart();
    }

    /**
     * 创建渐变动画实例
     *
     * @param toValue 目标透明度
     * @return 配置好的渐变动画对象
     */
    private static FadeTransition createFadeTransition(double toValue) {
        FadeTransition ft = new FadeTransition(DEFAULT_ANIM_DURATION);
        ft.setFromValue(DEFAULT_OPACITY);
        ft.setToValue(toValue);
        return ft;
    }

    /**
     * 添加临时样式类
     *
     * @param styleClass 样式类名称
     * @param duration   持续时间
     */
    private void addTempStyleClass(String styleClass, Duration duration) {
        getStyleClass().add(styleClass);
        new Timeline(new KeyFrame(duration, e ->
                getStyleClass().remove(styleClass)
        )).play();
    }


}